#!/usr/bin/env python
# -*- coding: utf-8 -*-
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = 'Eto Demerzel'
from copy import deepcopy
import sys
import sqlite3dump as db

def dumpIntoDb(tree, db_name):
        nodes  = deepcopy(zip(map( lambda x: x.id, tree), map( lambda x: x.leftkey, tree), map( lambda x: x.rightkey, tree)))
        edges = deepcopy(zip(  map( lambda x: x.id, tree), map( lambda x: x.pid, tree)))
        db.create_table(db_name, nodes, edges)
        return None

def findMaxLevel(tree):
    levels = []
    for node in tree:
        levels.append(node.level)
    return max(levels)

class Node:
    def __init__(self, id, pid, level, leftkey, rightkey):
        self.id = id
        self.pid = pid
        self.level = level
        self.leftkey = leftkey
        self.rightkey = rightkey

class Nested:
    def __init__(self, tree):
        self.tree = tree

    @staticmethod
    def getNodeById(self, node_id):
            for node in self.tree:
                if node_id == node.id:
                    return node
            print "There's no such node, please check id-parameter"
            sys.exit()

    def addNode(self, target_id, level):
        #print "Adding node to node id:", target_id
        right_key = self.getNodeById(self, target_id).rightkey
        id = self.getNodeById(self, target_id).id

        for node in self.tree:
            if node.leftkey > right_key:
                node.rightkey += 2
                node.leftkey += 2
            if node.rightkey >= right_key and node.leftkey < right_key:
                node.rightkey += 2
        self.tree.append(Node(len(tree)+1, id,  level+1, right_key, right_key+1))

        return self

    def deleteNode(self, target_id, level):
        #level is unnecessary
        node_del = (self.getNodeById(self, target_id))
        right_key = node_del.rightkey
        left_key = node_del.leftkey

        #deleting
        for node in self.tree:
            if node.leftkey >= left_key and node.rightkey <= right_key:
                self.tree.remove(node)
                node.pid = deepcopy(node.id)
        #new index of tree
        for node in self.tree:
            if node.rightkey > right_key:
                if node.leftkey >= left_key:
                    node.leftkey = node.leftkey - (right_key - left_key + 1)
                node.rightkey = node.rightkey - (right_key - left_key + 1)
        return self

    @staticmethod
    def representSubTree(self, subtree):
        ordered_list = []
        for node in subtree:
            ordered_list.append([node.leftkey,node.id])
        list = (dict(ordered_list).keys())
        list.sort()
        for l in xrange(len(list)):
            for node in subtree:
                if list[l] == node.leftkey:
                    print '*'*(node.level), 'id:', node.id, 'lk:', node.leftkey, 'rk:', node.rightkey
        print '------------->'
        return self

    def representTree(self):
        print "Representing tree..."
        ordered_list = []
        for node in (self.tree):
            ordered_list.append([node.leftkey,node.id])

        list = (dict(ordered_list).keys())
        list.sort()

        for l in xrange(len(list)):
            for node in self.tree:
                if list[l] == node.leftkey:
                    print '*'*(node.level), 'id:',node.id #, 'lk:', node.leftkey, 'rk:', node.rightkey
        print '------------->'
        return self

    def showDescendantsById(self, target_id):
        print "Showing descendants by given node-id...node-id is ", target_id
        lk = self.getNodeById(self, target_id).leftkey
        rk = self.getNodeById(self, target_id).rightkey

        tree = []
        for node in self.tree:
            if node.rightkey <= rk and node.leftkey >= lk:
                tree.append(node)
        self.representSubTree(self, tree)
        return  self

    def showParentBranchById(self, target_id):
        print "Showing parent branch of given node_-id...node-id is ", target_id
        lk = self.getNodeById(self, target_id).leftkey
        rk = self.getNodeById(self, target_id).rightkey

        tree = []
        for node in self.tree:
            if node.rightkey >= rk and node.leftkey <= lk:
                tree.append(node)

        self.representSubTree(self, tree)
        return  self

    def showFullBranchById(self, target_id):
        print "Showing full branch by node-id...node-id is ", target_id
        lk = self.getNodeById(self, target_id).leftkey
        rk = self.getNodeById(self, target_id).rightkey

        tree = []
        for node in self.tree:
            if node.rightkey > lk and node.leftkey < rk:
                tree.append(node)
        self.representSubTree(self, tree)
        return  self

    def moveNode(self, node_move_id, parent_id):

        node_move = deepcopy(self.getNodeById(self, node_move_id))
        node_parent = deepcopy(self.getNodeById(self, parent_id))
        node_size = node_move.rightkey - node_move.leftkey + 1

        for node in self.tree:
            if node.leftkey >= node_move.leftkey and node.rightkey <= node_move.rightkey:
                node.leftkey= 0 - node.leftkey
                node.rightkey= 0 - node.rightkey
                if node.level > node_move.level:
                    node.level = node_parent.level - (node_move.level-node.level) + 1
                else:
                    node.level = node_parent.level + 1
        for node in self.tree:
            if node.leftkey> node_move.rightkey:
                node.leftkey = node.leftkey - node_size
        for node in self.tree:
            if node.rightkey> node_move.rightkey:
                node.rightkey = node.rightkey - node_size
        if node_parent.rightkey>node_move.rightkey:
            auxrgt = node_parent.rightkey - node_size
        else:
            auxrgt = node_parent.rightkey

        for node in self.tree:
            if node.leftkey >= auxrgt:
                node.leftkey = node.leftkey + node_size

        for node in self.tree:
            if node.rightkey >= auxrgt:
                node.rightkey = node.rightkey + node_size
        if node_parent.rightkey>node_move.rightkey:
            auxr = node_parent.rightkey - node_move.rightkey - 1
        else:
            auxr = node_parent.rightkey - node_move.rightkey - 1 + node_size

        for node in self.tree:
            if node.leftkey <= 0 - node_move.leftkey and node.rightkey >= 0 - node_move.rightkey:
                node.leftkey = 0 - node.leftkey + auxr
                node.rightkey = 0 - node.rightkey + auxr

        node_move =(self.getNodeById(self, node_move_id))
        node_move.pid = node_parent.id
        node_move.level = node_parent.level+1

        return self

tree = []
tree.append(Node(1,0,0,1,2))
n = Nested(tree)

n.addNode(1,0)
n.addNode(1,0)
n.addNode(1,0)
n.addNode(1,0)
n.addNode(1,0)
n.addNode(1,0)

n.addNode(5,1)
n.addNode(5,1)
n.addNode(5,1)
n.addNode(5,1)
n.addNode(11,2)
n.addNode(8,2)
n.addNode(11,2)
n.addNode(14,3)

#n.moveNode(7,4)
dumpIntoDb(n.tree, "db_before_move.sqlite")
#n.deleteNode(9,0)
#n.representTree()
n.moveNode(11,4)
dumpIntoDb(n.tree, "db_after_move.sqlite")
n.deleteNode(5,1)
dumpIntoDb(n.tree,"db_deleting_5.sqlite")
#n.showDescendantsById(5)
#n.showParentBranchById(5)
#n.showFullBranchById(5)


